package com.ymatou.iapi.optrade.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.client.ClientProtocolException;

import com.ymatou.iapi.optrade.parameter.enums.AuthenticateFeeTypeEnum;
import com.ymatou.iapi.optrade.parameter.req.ApplyRefundReq;
import com.ymatou.iapi.optrade.parameter.req.ApplyRefundV2Req;
import com.ymatou.iapi.optrade.parameter.req.ApproveRefundBillReq;
import com.ymatou.iapi.optrade.parameter.req.RejectRefundBillReq;
import com.ymatou.iapi.optrade.parameter.utill.Utils;
import com.ymatou.iapi.optrade.parameter.vo.SalesRefundInfoVo;
import com.ymatou.iapi.optrade.resp.Order;
import com.ymt.base.YmatouEasyCall;
import com.ymt.core.tool.Logger;
import com.ymttest.business.service.YMTTrading.TradingCallService;
import com.ymttest.database.model.AccountEntry;
import com.ymttest.database.sharding.db.sharding.model.OrderDetailPo;
import com.ymttest.database.sharding.db.sharding.model.RefundBillPo;
import com.ymttest.database.sharding.db.sharding.model.RefundFundPo;
import com.ymttest.database.sharding.db.sharding.model.UserRefundFundDetailPo;
import com.ymttest.database.sqlwapper.AccountWapper;
import com.ymttest.utils.DataUtil;

public class RefundService {

	public static ApplyRefundReq buildStandApplyRefundReq(Order order) {

		return buildStandApplyRefundReq(order, 0);
	}

	public static ApplyRefundReq buildStandApplyRefundReq(Order order,
			int productNum) {

		long orderId = order.getOrderId();

		ApplyRefundReq req = new ApplyRefundReq();

		req.setOrderId(orderId);

		// 订单商品明细
		List<SalesRefundInfoVo> salesRefundInfoList = new ArrayList<SalesRefundInfoVo>();

		for (int i = 0; i < order.getOrderDetailPoList().size(); i++) {

			OrderDetailPo orderDetailPo = order.getOrderDetailPoList().get(i);
			int refundProductNum = 0;
			String catalogId = orderDetailPo.getCatalogId();

			if (productNum > orderDetailPo.getProductCount()) {
				Logger.comment("退款数量大于订单购买的数量");
			}

			if (productNum > 0) {
				refundProductNum = productNum;
			}

			if (productNum == 0) {
				refundProductNum = orderDetailPo.getProductCount();
			}

			SalesRefundInfoVo salesRefundInfo = new SalesRefundInfoVo();

			// 计算订单总价格 商品价格 X 数量+运费
			BigDecimal refoundAmout = (orderDetailPo.getProductPrice())
					.multiply(new BigDecimal(refundProductNum))
					.subtract(orderDetailPo.getSellerCouponAmount())
					.subtract(orderDetailPo.getYmtCouponAmount())
					.subtract(orderDetailPo.getYmtPromotionAmount())
					.subtract(
							Utils.zeroIfNull(orderDetailPo.getThirdpartyDiscount()))
					.add(orderDetailPo.getFreight())
					.add(RefundService.getUserAuthenticateFee(orderDetailPo,
							refundProductNum));
			
			// 退最后一个商品的时候并且全退，加上买家鉴别运费
			if (i == order.getOrderDetailPoList().size() - 1
					&& refundProductNum == orderDetailPo.getProductCount())
				refoundAmout = refoundAmout.add(order.getUserAuthenticateFreightFee());

			salesRefundInfo.setCatalogId(catalogId);

			salesRefundInfo.setRefundAmount(refoundAmout);
			salesRefundInfo.setRefundBillNo("TK" + i + orderId);
			salesRefundInfo.setRefundProductNum(refundProductNum);

			salesRefundInfoList.add(salesRefundInfo);
		}

		req.setSalesRefundInfoList(salesRefundInfoList);

		return req;
	}

	// 只申请订单中第一个商品的退款单
	public static ApplyRefundReq buildSingleApplyRefundReq(Order order)
			throws ClientProtocolException, IOException {

		long orderId = order.getOrderId();
		ApplyRefundReq req = new ApplyRefundReq();
		req.setOrderId(orderId);

		// 订单商品明细
		List<SalesRefundInfoVo> salesRefundInfoList = new ArrayList<SalesRefundInfoVo>();

		OrderDetailPo orderDetailPo = order.getOrderDetailPoList().get(0);
		int refundProductNum = 0;
		String catalogId = orderDetailPo.getCatalogId();

		refundProductNum = orderDetailPo.getProductCount();

		SalesRefundInfoVo salesRefundInfo = new SalesRefundInfoVo();

		// 计算订单总价格 商品价格 X 数量+运费
		BigDecimal refoundAmout = (orderDetailPo.getProductPrice())
				.multiply(new BigDecimal(refundProductNum))
				.subtract(orderDetailPo.getSellerCouponAmount())
				.subtract(orderDetailPo.getYmtCouponAmount())
				.subtract(orderDetailPo.getYmtPromotionAmount())
				.subtract(
						Utils.zeroIfNull(orderDetailPo.getThirdpartyDiscount()))
				.add(orderDetailPo.getFreight());

		salesRefundInfo.setCatalogId(catalogId);

		salesRefundInfo.setRefundAmount(refoundAmout);
		salesRefundInfo.setRefundBillNo("TK" + "0" + orderId);
		salesRefundInfo.setRefundProductNum(refundProductNum);

		salesRefundInfoList.add(salesRefundInfo);

		req.setSalesRefundInfoList(salesRefundInfoList);

		ApplySalesRefundCall applySalesRefundCall = new ApplySalesRefundCall();
		applySalesRefundCall.setData(false, req);

		applySalesRefundCall.callService();

		return req;

	}
	
	// 只申请订单中第一个商品的退款单
	public static ApplyRefundReq buildSingleApplyRefundReq(Order order,
			Boolean addUserAuthenticateFee, BigDecimal userAuthenticateFreightFee) throws ClientProtocolException,
			IOException {

		long orderId = order.getOrderId();
		ApplyRefundReq req = new ApplyRefundReq();
		req.setOrderId(orderId);

		// 订单商品明细
		List<SalesRefundInfoVo> salesRefundInfoList = new ArrayList<SalesRefundInfoVo>();

		OrderDetailPo orderDetailPo = order.getOrderDetailPoList().get(0);
		int refundProductNum = orderDetailPo.getProductCount();
		String catalogId = orderDetailPo.getCatalogId();
		
		SalesRefundInfoVo salesRefundInfo = new SalesRefundInfoVo();

		// 计算订单总价格 商品价格 X 数量+运费
		BigDecimal refoundAmout = (orderDetailPo.getProductPrice())
				.multiply(new BigDecimal(refundProductNum))
				.subtract(orderDetailPo.getSellerCouponAmount())
				.subtract(orderDetailPo.getYmtCouponAmount())
				.subtract(orderDetailPo.getYmtPromotionAmount())
				.subtract(
						Utils.zeroIfNull(orderDetailPo.getThirdpartyDiscount()))
				.add(orderDetailPo.getFreight());
		
		if (addUserAuthenticateFee)
			refoundAmout = refoundAmout.add(order.getUserAuthenticateFee(refundProductNum));
		
		refoundAmout = refoundAmout.add(userAuthenticateFreightFee);

		salesRefundInfo.setCatalogId(catalogId);

		salesRefundInfo.setRefundAmount(refoundAmout);
		salesRefundInfo.setRefundBillNo("TK" + "0" + orderId);
		salesRefundInfo.setRefundProductNum(refundProductNum);

		salesRefundInfoList.add(salesRefundInfo);

		req.setSalesRefundInfoList(salesRefundInfoList);

		ApplySalesRefundCall applySalesRefundCall = new ApplySalesRefundCall();
		applySalesRefundCall.setData(false, req);

		applySalesRefundCall.callService();

		return req;

	}

	// 创建订单中某个商品的退款单（全退）
	public static ApplyRefundReq buildSingleApplyRefundReq(Long orderId,
			OrderDetailPo orderDetailPo, BigDecimal freight)
			throws ClientProtocolException, IOException {

		return buildSingleApplyRefundReq(orderId, orderDetailPo, freight, null);
	}
	
	// 创建订单中某个商品的退款单
	public static ApplyRefundReq buildSingleApplyRefundReq(Long orderId,
			OrderDetailPo orderDetailPo, BigDecimal freight, Integer refundProductNum) throws ClientProtocolException,
			IOException {

		return buildSingleApplyRefundReq(orderId, orderDetailPo, freight, refundProductNum, null);
	}
	
	// 创建订单中某个商品的退款单
	public static ApplyRefundReq buildSingleApplyRefundReq(Long orderId,
			OrderDetailPo orderDetailPo, BigDecimal freight,
			Integer refundProductNum, String refundBillNo) throws ClientProtocolException,
			IOException {

		ApplyRefundReq req = new ApplyRefundReq();
		req.setOrderId(orderId);

		// 订单商品明细
		List<SalesRefundInfoVo> salesRefundInfoList = new ArrayList<SalesRefundInfoVo>();

		String catalogId = orderDetailPo.getCatalogId();

		if (Utils.zeroIfNull(refundProductNum) == 0)
			refundProductNum = orderDetailPo.getProductCount();

		SalesRefundInfoVo salesRefundInfo = new SalesRefundInfoVo();

		// 计算订单总价格 商品价格 X 数量+运费
		BigDecimal refoundAmout = (orderDetailPo.getProductPrice())
				.multiply(new BigDecimal(refundProductNum))
				.subtract(orderDetailPo.getSellerCouponAmount())
				.subtract(orderDetailPo.getYmtCouponAmount())
				.subtract(orderDetailPo.getYmtPromotionAmount())
				.subtract(
						Utils.zeroIfNull(orderDetailPo.getThirdpartyDiscount()))
				.add(freight)
				.add(RefundService.getUserAuthenticateFee(orderDetailPo,
						refundProductNum));

		salesRefundInfo.setCatalogId(catalogId);

		salesRefundInfo.setRefundAmount(refoundAmout);
		salesRefundInfo.setRefundBillNo(null == refundBillNo ? "TK" + "0"
				+ orderId : refundBillNo);
		salesRefundInfo.setRefundProductNum(refundProductNum);

		salesRefundInfoList.add(salesRefundInfo);

		req.setSalesRefundInfoList(salesRefundInfoList);

		return req;
	}
	
	/**
	 * 单个订单只有一个catalogId
	 * 创建订单第一个商品的退款单，商品一个一个退
	 * @param order
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static ApplyRefundReq buildSingleOneByOneApplyRefundReq(Order order)
			throws ClientProtocolException, IOException {

		ApplyRefundReq req = new ApplyRefundReq();
		
		req.setOrderId(order.getOrderId());
		
		OrderDetailPo orderDetailPo = order.getOrderDetailPoList().get(0);

		// 订单商品明细
		List<SalesRefundInfoVo> salesRefundInfoList = new ArrayList<SalesRefundInfoVo>();

		String catalogId = orderDetailPo.getCatalogId();

		for (int i = 0; i < orderDetailPo.getProductCount(); i++) {
			
			SalesRefundInfoVo salesRefundInfo = new SalesRefundInfoVo();

			// 计算订单总价格 商品价格 X 数量+运费
			BigDecimal refoundAmout = (orderDetailPo.getProductPrice())
					.multiply(new BigDecimal(1))
					.subtract(orderDetailPo.getSellerCouponAmount())
					.subtract(orderDetailPo.getYmtCouponAmount())
					.subtract(orderDetailPo.getYmtPromotionAmount())
					.subtract(
							Utils.zeroIfNull(orderDetailPo
									.getThirdpartyDiscount()))
					// 第一次退款退订单运费
					.add(i == 0 ? order.getOrderFreight() : BigDecimal.ZERO)
					.add(RefundService.getUserAuthenticateFee(orderDetailPo,
							1))
					.add(i == orderDetailPo.getProductCount() - 1 ? order.getUserAuthenticateFreightFee() : BigDecimal.ZERO);

			salesRefundInfo.setCatalogId(catalogId);

			salesRefundInfo.setRefundAmount(refoundAmout);
			salesRefundInfo.setRefundBillNo("TK" + i + +order.getOrderId());
			salesRefundInfo.setRefundProductNum(1);

			salesRefundInfoList.add(salesRefundInfo);

			req.setSalesRefundInfoList(salesRefundInfoList);
		}

		ApplySalesRefundCall applySalesRefundCall = new ApplySalesRefundCall();
		applySalesRefundCall.setData(false, req);

		applySalesRefundCall.callService();

		return req;
	}

	public static void applyRefundCall(ApplyRefundReq applyRefundReq) {

		ApplySalesRefundCall applySalesRefundCall = new ApplySalesRefundCall();
		applySalesRefundCall.setData(false, applyRefundReq);

		try {

			applySalesRefundCall.callService();

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 根据 Order order 创建一个退款申请单. 订单下所有商品全额退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq applyRefund(Order order) {

		ApplyRefundReq req = buildStandApplyRefundReq(order);

		applyRefundCall(req);

		return req;

	}

	/**
	 * 根据 Order order 创建一个退款申请单. 订单下部分商品全额退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq applyRefund(Order order, int productNum) {

		return applyRefund(order, productNum, null);
	}
	
	/**
	 * 根据 Order order 创建一个退款申请单. 订单下第一个商品根据退款金额退款，其他商品全额退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq applyRefund(Order order, BigDecimal applyRefundAmount) {

		return applyRefund(order, 0, applyRefundAmount);
	}
	
	/**
	 * 根据 Order order 创建一个退款申请单. 订单下第一个商品根据退款金额退款，其他商品全额退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq applyRefund(Order order, Integer productNum, BigDecimal applyRefundAmount) {

		ApplyRefundReq req = buildStandApplyRefundReq(order, productNum);
		
		if (applyRefundAmount != null)
			req.getSalesRefundInfoList().get(0).setRefundAmount(applyRefundAmount);

		applyRefundCall(req);

		return req;

	}

	public static void rejectRefundCall(ApplyRefundReq req) {

		SalesRefundFailCall salesrefundfailCall = new SalesRefundFailCall();
		RejectRefundBillReq salesrefundfailreq = new RejectRefundBillReq();

		salesrefundfailreq.setOrderId(req.getOrderId());

		salesrefundfailreq.setTopspeedRefund(false);

		for (SalesRefundInfoVo salesRefundInfoVo : req.getSalesRefundInfoList()) {

			salesrefundfailreq.setRefundBillNo(salesRefundInfoVo
					.getRefundBillNo());

			salesrefundfailCall.setData(false, salesrefundfailreq);

			try {
				salesrefundfailCall.callService();

			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}

	/**
	 * 根据 Order order 退款拒绝.
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq rejectRefundBill(Order order) {

		ApplyRefundReq req = applyRefund(order);

		rejectRefundCall(req);

		return req;

	}

	/**
	 * 根据 Order order 执行退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq approveRefund(Order order) {

		ApplyRefundReq req = applyRefund(order);

		approveRefundBillCall(req);

		return req;

	}
	
	/**
	 * 根据 Order order 执行退款
	 * 
	 * @param order
	 * @return
	 */
	public static ApplyRefundReq approveRefund(Order order, int num) {

		ApplyRefundReq req = applyRefund(order, num);

		approveRefundBillCall(req);

		return req;

	}
	
	/**
	 * 鉴定中心退款，并执行退款
	 * @param order
	 * @return
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 */
	public static ApplyRefundV2Req approveRefundViaAuthenticateCenter(
			Order order) throws ClientProtocolException, IOException {

		ApplyRefundV2Req applyRefundReq = new ApplyRefundV2Req();
		ApplyRefundV2Call applySalesRefundCall = new ApplyRefundV2Call();
		;

		Long orderId = order.getOrderId();
		OrderDetailPo orderDetailPo = order.getOrderDetailPoList().get(0);
		Integer refundedProductCount = orderDetailPo.getProductCount();

		BigDecimal totalApplyAmount = orderDetailPo
				.getProductPrice()
				.multiply(new BigDecimal(refundedProductCount))
				.add(order.getOrderFreight())
				.add(order.getUserAuthenticateFee(refundedProductCount).add(
						order.getUserAuthenticateFreightFee()));

		applyRefundReq.setOrderId(orderId);

		applyRefundReq.setApplyRefundFreight(order.getOrderFreight());
		applyRefundReq.setApplyRefundCount(refundedProductCount);
		applyRefundReq.setApplyRefundAmount(totalApplyAmount);
		applyRefundReq.setCatalogId(orderDetailPo.getCatalogId());
		applyRefundReq.setApplyRefundAuthenticateFee(order
				.getUserAuthenticateFee(refundedProductCount).add(
						order.getUserAuthenticateFreightFee()));
		applyRefundReq.setRefundType(1);

		applyRefundReq.setRefundBillNo(String.format("TK%s", orderId));

		applySalesRefundCall.setData(applyRefundReq);
		applySalesRefundCall.callService();
		
		ApproveRefundBillReq salesrefundsuccessReq = new ApproveRefundBillReq();
		SalesRefundSuccessCall salesrefundsuccessCall = new SalesRefundSuccessCall();

		salesrefundsuccessReq.setOrderId(applyRefundReq.getOrderId());
		salesrefundsuccessReq.setOperatorInfo("autotest");

		salesrefundsuccessReq.setRefundBillNo(applyRefundReq
				.getRefundBillNo());
		salesrefundsuccessCall.setData(false, salesrefundsuccessReq);

		try {
			salesrefundsuccessCall.callService();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return applyRefundReq;
	}

	/**
	 * approveRefundBillCall
	 * 
	 * @param approveRefundBillReq
	 */
	public static void approveRefundBillCall(ApplyRefundReq applyRefundReq) {

		ApproveRefundBillReq salesrefundsuccessReq = new ApproveRefundBillReq();
		SalesRefundSuccessCall salesrefundsuccessCall = new SalesRefundSuccessCall();

		salesrefundsuccessReq.setOrderId(applyRefundReq.getOrderId());
		salesrefundsuccessReq.setOperatorInfo("autotest");

		for (SalesRefundInfoVo salesRefundInfoVo : applyRefundReq
				.getSalesRefundInfoList()) {

			salesrefundsuccessReq.setRefundBillNo(salesRefundInfoVo
					.getRefundBillNo());
			salesrefundsuccessCall.setData(false, salesrefundsuccessReq);
		}

		try {
			salesrefundsuccessCall.callService();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 退款业务表（refund_bill）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyRefundBillDb(RefundBillPo expected,
			RefundBillPo actual) {

		Logger.comment(String.format("校验 退款业务表（refund_bill） refundBillNo : %s",
				expected.getRefundBillNo()));

		verify(expected.getFreight(), actual.getFreight(), "验证数据库Freight");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库AddTime跟系统当前时间差为3分钟内");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库UpdateTime跟系统当前时间差为3分钟内");

		verify(expected.getOrderId(), actual.getOrderId(), "验证数据库OrderId");
		verify(expected.getSellerId(), actual.getSellerId(), "验证数据库SellerId");
		verify(expected.getUserId(), actual.getUserId(), "验证数据库UserId");
		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库ThirdpartyDiscount");
		verify(expected.getCatalogId(), actual.getCatalogId(), "验证数据库CatalogId");
		verify(expected.getProductCount(), actual.getProductCount(),
				"验证数据库ProductCount");
		verify(expected.getRefundBillStatus(), actual.getRefundBillStatus(),
				"验证数据库RefundBillStatus");
		verify(expected.getTopspeedRefund(), actual.getTopspeedRefund(),
				"验证数据库TopspeedRefund");
		verify(expected.getDeductedCouponAmount() == null ? BigDecimal.ZERO
				: expected.getDeductedCouponAmount(),
				actual.getDeductedCouponAmount(), "验证数据库DeductedCouponAmount");
		verify(expected.getNoSettlementCouponAmount() == null ? BigDecimal.ZERO
				: expected.getNoSettlementCouponAmount(),
				actual.getNoSettlementCouponAmount(),
				"验证数据库NoSettlementCouponAmount");

		verify(expected.getAfterReceiving(), actual.getAfterReceiving(),
				"验证数据库AfterReceiving");
		verify(expected.getRefundBillNo(), actual.getRefundBillNo(),
				"验证数据库RefundBillNo");

		verify(expected.getTotalAmount(), actual.getTotalAmount(),
				"验证数据库TotalAmount");

		verify(expected.getAccountAmount() == null ? BigDecimal.ZERO
				: expected.getAccountAmount(), actual.getAccountAmount(),
				"验证数据库accountAmount");

		verify(expected.getCardAmount() == null ? BigDecimal.ZERO
				: expected.getCardAmount(), actual.getCardAmount(),
				"验证数据库cardAmount");

		verify(expected.getThirdpartyAmount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyAmount(), actual.getThirdpartyAmount(),
				"验证数据库thirdpartyAmount");

		verify(expected.getRefundStatus(), actual.getRefundStatus(),
				"验证数据库RefundStatus");

		verify(expected.getRebateAmount() == null ? BigDecimal.ZERO
				: expected.getRebateAmount(), actual.getRebateAmount(),
				"验证数据库rebateAmount");
		verify(expected.getUserAuthenticateFee() == null ? BigDecimal.ZERO
				: expected.getUserAuthenticateFee(), actual.getUserAuthenticateFee(),
				"验证数据库userAuthenticateFee");
		verify(expected.getRefundType(), actual.getRefundType(),
				"验证数据库refundType");
	}

	/**
	 * 用户退款资金详情表（user_refund_fund_detail）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyUserRefundFundDetailDb(
			UserRefundFundDetailPo expected, UserRefundFundDetailPo actual) {

		Logger.comment(String
				.format("验证退用户退款资金详情表（user_refund_fund_detail） OrderId :%s payment_id :%s",
						expected.getOrderId(), expected.getPaymentId()));

		verify(true, Utils.calcTimeSpanMin(actual.getUpdateTime()) < 3,
				"验证数据库UpdateTime跟系统当前时间差为3分钟内");
		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库AddTime跟系统当前时间差为3分钟内");

		verify(expected.getBizType(), actual.getBizType(), "验证数据库BizType");
		verify(expected.getPaymentId(), actual.getPaymentId(), "验证数据库PaymentId");

		verify(expected.getMemo(),
				actual.getMemo() == null ? "0" : actual.getMemo(), "验证数据库Memo");

		verify(expected.getAccountAmount(), actual.getAccountAmount(),
				"验证数据库AccountAmount");

		verify(expected.getAccountRefundStatus(),
				actual.getAccountRefundStatus(), "验证数据库AccountRefundStatus");

		verify(expected.getThirdpartyAmount(), actual.getThirdpartyAmount(),
				"验证数据库ThirdpartyAmount");
		verify(expected.getThirdpartyRefundStatus(),
				actual.getThirdpartyRefundStatus(),
				"验证数据库ThirdpartyRefundStatus");

		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库ThirdpartyDiscount");

		verify(expected.getRebateAmount() == null ? BigDecimal.ZERO
				: expected.getRebateAmount(), actual.getRebateAmount(),
				"验证数据库RebateAmount");
		/*
		 * verify(expected.getAccountRefundTime(),
		 * actual.getAccountRefundTime(), "验证数据库AccountRefundTime");
		 */

		verify(true,
				Utils.calcTimeSpanMin(actual.getThirdpartyRefundTime()) < 2,
				"验证数据库ThirdpartyRefundTime跟系统当前时间差为2分钟内");

		verify(expected.getRetryTimes(), actual.getRetryTimes(),
				"验证数据库RetryTimes");
	}

	/**
	 * 退款业务表（refund_fund）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyRefundFundDb(RefundFundPo expected,
			RefundFundPo actual) {

		Logger.comment(String.format("验证退款业务表（refund_fund） OrderId :%s",
				expected.getOrderId()));

		verify(expected.getFreight(), actual.getFreight(), "验证数据库Freight");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		verify(expected.getOrderId(), actual.getOrderId(), "验证数据库OrderId");

		verify(expected.getDeductedCouponAmount() == null ? BigDecimal.ZERO
				: expected.getDeductedCouponAmount(),
				actual.getDeductedCouponAmount(), "验证数据库DeductedCouponAmount");
		
		verify(expected.getDeductedAmount() == null ? BigDecimal.ZERO
				: expected.getDeductedAmount(),
				actual.getDeductedAmount(), "验证数据库DeductedAmount");

		verify(expected.getUserThirdpartyAmount(),
				actual.getUserThirdpartyAmount(), "验证数据库thirdpartyAmount");
		verify(expected.getUserAccountAmount(), actual.getUserAccountAmount(),
				"验证数据库userAccountAmount");

		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库thirdpartyDiscount");

		verify(expected.getUserRebateAmount() == null ? BigDecimal.ZERO
				: expected.getUserRebateAmount(), actual.getUserRebateAmount(),
				"验证数据库UserRebateAmount");
		verify(expected.getUserAuthenticateFee() == null ? BigDecimal.ZERO
				: expected.getUserAuthenticateFee(), actual.getUserAuthenticateFee(),
				"验证数据库UserAuthenticateFee");
	}

	private static void verify(Object expected, Object actuaL, String desc) {

		if (expected instanceof java.math.BigDecimal) {
			DataUtil.verifyDecimalEquals(expected, actuaL, desc);
		} else {
			if (expected != null) {
				Logger.verifyEquals(expected, actuaL, desc);
			}
		}
	}

	/**
	 * 查询用户流水
	 * 
	 * @param userId
	 * @param orderId
	 * @param originalNo
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static AccountEntry getAccountEntry(long userId, String bizno,
			String originalNo) {

		Map m = new HashMap();

		m.put("userId", userId);
		m.put("bizno", bizno);
		m.put("originalNo", originalNo);
		m.put("bizcode", "300006");

		AccountEntry res = null;
		try {

			res = new AccountWapper().selectAccountEntryByBizNo(m).get(0);

		} catch (Exception e) {

			e.printStackTrace();
		}

		return res;
	}

	/**
	 * 查询用户流水
	 * 
	 * @param userId
	 * @param orderId
	 * @param originalNo
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static AccountEntry getRefundRebateAmountAccountEntry(long userId,
			String bizno, String originalNo) {

		Map m = new HashMap();

		m.put("userId", userId);
		m.put("bizno", bizno);
		m.put("originalNo", originalNo);
		m.put("bizcode", "300044");

		AccountEntry res = null;
		try {

			res = new AccountWapper().selectAccountEntryByBizNo(m).get(0);

		} catch (Exception e) {

			e.printStackTrace();
		}

		return res;
	}

	/**
	 * 运费退款 如果申请的退款金额小于商品的实际支付金额（不包括运费），则不退回运费
	 * 
	 * @param orderDetailPo
	 * @param applyRefundAmount
	 * @return
	 */
	public static BigDecimal apportionFreight(OrderDetailPo orderDetailPo,
			BigDecimal applyRefundAmount, int applyRefundCount) {

//		BigDecimal totalProductRealPayAmount = Utils
//				.zeroIfNull(orderDetailPo.getProductPrice())
//				.multiply(new BigDecimal(orderDetailPo.getProductCount()))
//				.subtract(Utils.zeroIfNull(orderDetailPo.getRebatePaidAmount()));
		
		BigDecimal totalProductRealPayAmount = TradingCallService
				.getOrderDetailPaidAmountExcludeFreight(orderDetailPo);
		
		// 退款运费 = 退款总金额 - (商品总支付价格 / 商品数量 × 退款数量)
		BigDecimal refundFreight = applyRefundAmount
				.subtract(totalProductRealPayAmount
						.divide(new BigDecimal(orderDetailPo.getProductCount()),
								20, RoundingMode.HALF_UP)
						.multiply(new BigDecimal(applyRefundCount))
						.setScale(2, RoundingMode.HALF_UP));

		return refundFreight.compareTo(BigDecimal.ZERO) == -1 ? BigDecimal.ZERO
				: refundFreight;
	}

	/**
	 * 返点金额的退款
	 * 
	 * @param orderDetailPo
	 * @param applyRefundAmount
	 * @return
	 */
	public static BigDecimal apportionRefundRebate(OrderDetailPo orderDetailPo,
			BigDecimal applyRefundAmount) {

		BigDecimal productRealPayAmount = TradingCallService
				.getOrderDetailPaidAmountExcludeFreight(orderDetailPo);

		if (applyRefundAmount.compareTo(productRealPayAmount) >= 0)
			return orderDetailPo.getRebatePaidAmount();
		else
			return devideThenMultiply(applyRefundAmount, productRealPayAmount,
					Utils.zeroIfNull(orderDetailPo.getRebatePaidAmount()));
	}

	public static BigDecimal devideThenMultiply(BigDecimal dividend,
			BigDecimal divisor, BigDecimal multiplier) {
		return dividend.divide(divisor, MathContext.DECIMAL32)
				.multiply(multiplier).setScale(2, RoundingMode.HALF_UP);
	}

	/**
	 * 退款失败补偿
	 */
	public static void retryRefund() {

		YmatouEasyCall retryRefundCall = new YmatouEasyCall("", "POST", "JSON");

		String json = "{\"minuteBefore\":" + 0 + "}";

		retryRefundCall
				.setUrl("http://operate.trading.iapi.ymatou.com/api/SalesRefund/retryRefundInstruction");

		retryRefundCall.setData(json);

		Logger.comment("退款补偿");
		try {
			retryRefundCall.callService();

		} catch (Exception e) {

			e.printStackTrace();

		}
	}

	/**
	 * 接单之后，所有订单上商品所有款都退完后，订单变更为用户取消，给商家结算剩余金额
	 * 
	 * @param orderId
	 */
	public static void settleLeftAmtAfterCancelled(long orderId) {

		YmatouEasyCall settleLeftAmtAfterCancelled = new YmatouEasyCall("",
				"POST", "JSON");
		String json = "{\"orderId\":" + orderId + "}";

		settleLeftAmtAfterCancelled
				.setUrl("http://settlement.iapi.ymatou.com/api/settleLeftAmtAfterCancelled");

		settleLeftAmtAfterCancelled.setData(json);

		Logger.comment("接单后，退货退完后，订单为用户取消，给商家结算剩余金额");
		try {
			settleLeftAmtAfterCancelled.callService();
		} catch (Exception e) {

			e.printStackTrace();

		}
	}
	
	/**
	 * 返回商品的买家可退鉴定费
	 * @param orderDetailPo
	 * @param productCount
	 * @return
	 */
	public static BigDecimal getUserAuthenticateFee(
			OrderDetailPo orderDetailPo, Integer productCount) {
		return Utils.falseIfNull(orderDetailPo.getAuthenticateFlag() == true)
				&& Utils.zeroIfNull(orderDetailPo.getAuthenticateFeeType()) == AuthenticateFeeTypeEnum.BUYER
						.getCode() ? Utils.zeroIfNull(
				orderDetailPo.getAuthenticateFee()).multiply(
				new BigDecimal(productCount)) : BigDecimal.ZERO;
	}

	public static void main(String... args) {

		// System.out.println(RefundService.getAccountEntry(20238699,
		// "7311848699_TK07311848699_1", "TK07311848699").getAmount());

		System.out.println();
	}
}
